//RingQueue.hpp
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <semaphore.h>
using namespace std;
#define SIZE 5
template<class T>
class RingQueue
{
    public:
        RingQueue()
        :_ring(SIZE)
        {
            sem_init(&_customer,0,0);
            sem_init(&_productor,0,_capacity);
            _pos_customer=_pos_productor=0;
            pthread_mutex_init(&_mutex_customer,nullptr);
            pthread_mutex_init(&_mutex_productor,nullptr);
        }

        
    ~RingQueue()
    {
        sem_destroy(&_customer);
        sem_destroy(&_productor);

        pthread_mutex_destroy(&_mutex_customer);
        pthread_mutex_destroy(&_mutex_productor);
    }

        void push(const T& data)
        {
            sem_wait(&_productor);//等待信号量，如果有就申请成功
            pthread_mutex_lock(&_mutex_productor);
            _pos_productor%=_capacity;//保证环形队列
            _ring[_pos_productor++]=data;
            pthread_mutex_unlock(&_mutex_productor);
            sem_post(&_customer);//此时有数据了，唤醒消费者
        }

        void pop(T* data)
        {
            sem_wait(&_customer);//如果申请失败，就阻塞等待
            pthread_mutex_lock(&_mutex_customer);
            _pos_customer%=_capacity;
            *data=_ring[_pos_customer++];
            pthread_mutex_unlock(&_mutex_customer);
            sem_post(&_productor);//原子的
        }



    private:
    vector<T> _ring;//环形队列
    sem_t _customer;//消费者的信号量，只有消费者关心的数据
    sem_t _productor;//生产者的信号量，只有生产者关心的空间
    int _pos_customer;//消费位置；保证环形队列的特性而不越界
    int _pos_productor;//生产位置；保证环形队列的特性而不越界
    pthread_mutex_t _mutex_productor;//来限制生产者线程的锁
    pthread_mutex_t _mutex_customer;//来限制消费者线程的锁
    int _capacity=SIZE;//环形队列的大小
};
